﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace StringVal
{
    public static class StringHelper
    {
        /// <summary>
        /// Returns the Value Type equivalent of a String.
        /// Copyright (c) 2010 Shine Xavier
        /// </summary>
        public static ValueType GetValue(this string s)
        {
            int _stringLength = s.Length;
            string _typeName = "StringVal";
            AssemblyName _assemblyName = new AssemblyName();
            _assemblyName.Name = "IamOnTopOfTheWorld";
            AssemblyBuilder _newAssembly = 
            System.Threading.Thread.GetDomain().DefineDynamicAssembly(_assemblyName, AssemblyBuilderAccess.Run);
            ModuleBuilder _newModule = _newAssembly.DefineDynamicModule("StringUtils");
            TypeBuilder _newType = _newModule.DefineType(_typeName, 
                                 TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.SequentialLayout | TypeAttributes.Serializable, 
                                 typeof(ValueType));
            FieldBuilder field;
            for (int i=0;i<_stringLength;i++)
            {
                field = _newType.DefineField(string.Format("c{0}_{1}", i, Char.ConvertToUtf32(s, i)), typeof(bool), FieldAttributes.Public);
            }
            Type type = _newType.CreateType();
            return (ValueType)_newAssembly.CreateInstance(_typeName);
        }

        /// <summary>
        /// Returns the String equivalent o nnf Type :: StringVal
        /// Copyright (c) 2010 Shine Xavier
        /// </summary>
        public static string GetString(this ValueType valType)
        {
            string sOutput = @"Error::Expected Value Type-""StringVal""";
            if (valType.GetType().Assembly.GetName().Name.Equals("IamOnTopOfTheWorld") && 
                valType.GetType().Module.ScopeName.Equals("StringUtils") && 
                valType.GetType().Name.Equals("StringVal"))
            {
                var query = from m in valType.GetType().GetFields()
                            select m;
                StringBuilder sBuilder = new StringBuilder(query.Count<FieldInfo>());
                string fldName;
                int utfCharCode;
                foreach (FieldInfo fldInfo in query)
                {
                    fldName = fldInfo.Name;
                    utfCharCode = int.Parse(fldName.Substring(fldName.IndexOf("_") + 1));
                    sBuilder = sBuilder.Append(Char.ConvertFromUtf32(utfCharCode));
                }
                sOutput = sBuilder.ToString();
            }
            return sOutput;
        }

        /// <summary>
        /// Returns the byte size of a structure whose type is 'type', as stored in managed memory.
        /// Courtesy: http://msdn.microsoft.com/en-us/library/eahchzkf.aspx
        /// This function is explicity excempted from Copyright (c) 2010 Shine Xavier (owing to courtesy above)
        /// </summary>
        public static int GetManagedSize(this Type type)
        {
            var method = new DynamicMethod("GetManagedSizeImpl",
              typeof(uint), 
              new Type[0],
              false);
            ILGenerator gen = method.GetILGenerator();
            gen.Emit(OpCodes.Sizeof, type);
            gen.Emit(OpCodes.Ret);
            var func = (Func<uint>)method.CreateDelegate(typeof(Func<uint>));
            return checked((int)func());
        }
    }

    /// <summary>
    /// Test Harness!
    /// Copyright (c) 2010 Shine Xavier
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            string x = @"Mary had a little lamb!";//Provide your Input String here...
            Console.WriteLine(String.Format(@"Initialized String -> {0}",x));
            ValueType y = x.GetValue();//Converts the string to a value type
            Console.WriteLine(String.Format(@"String Converted to Value of Type -> {0} || Size -> {1} bytes", 
                y.GetType().Name, 
                y.GetType().GetManagedSize()));
            Console.WriteLine(String.Format(@"Recovered String from it's equivalent Value Type -> {0}", 
                y.GetString()));//Converts the value type to String
            Console.Read();
        }
    }
}
